package task

import (
	"database/sql"
	"log/slog"
	"time"

	"torler.com/qingyue/apps/spider/internal/core"
	"torler.com/qingyue/common/types"
	"torler.com/qingyue/pkg/logger"
	"torler.com/qingyue/pkg/tools"
)

type TaskCorn string

const (
	CORN_EVERY_1M  = TaskCorn("@every 1m")
	CORN_EVERY_2M  = TaskCorn("@every 2m")
	CORN_EVERY_5M  = TaskCorn("@every 5m")
	CORN_EVERY_10M = TaskCorn("@every 10m")
	CORN_EVERY_20M = TaskCorn("@every 2m")
	CORN_EVERY_30M = TaskCorn("@every 3m")
	CORN_EVERY_H   = TaskCorn("@every hour")
)

// Task 代表一个可执行的任务实体
//
// Task是任务管理系统中的核心结构，包含任务的所有配置信息和运行时状态。
// 它支持多种运行模式，包括一次性任务和定时任务，并提供了参数传递、
// 优先级设置、父子任务关联等功能。
type Task struct {
	ctx              *core.AppContext // 应用上下文，包含数据库连接、日志等全局资源
	mgr              *TaskManager     // 任务管理器引用
	id               string           // 任务唯一标识符，通过任务名称MD5生成
	pid              string           // 父任务ID，用于建立任务间的层级关系。此值不空时，表示当前任务为子任务
	name             types.TaskName   // 任务名称
	single           bool             // 是否为单例任务，单例任务不能同时运行多个实例
	runMode          types.RunMode    // 任务运行模式（一次性任务或定时任务）
	corn             TaskCorn         // Cron表达式，用于定时任务的调度规则
	runOnceWhenAdded bool             // 任务添加时是否立即执行,默认值为true
	priority         int              // 任务优先级，数值越大优先级越高
	RunnerName       types.RunnerName // 任务执行器名称，指定负责执行该任务的组件
	params           map[string]any   // 任务参数，用于向执行器传递自定义数据
	result           map[string]any   // 任务执行结果，用于存储任务执行后的结果数据
	addTime          time.Time        // 任务添加时间
	startTime        time.Time        // 任务开始执行时间
	endTime          time.Time        // 任务结束执行时间
	state            types.TaskStatus // 任务当前状态
	delay            time.Duration    // 延时执行时间
	info             *TaskInfo        // 任务定义信息，对应sp_task_info表
	record           *TaskRunInfo     // 任务执行记录，对应sp_task_record表
	logger           *slog.Logger     // 任务专用日志记录器
	sched            bool             // 标记任务是否已经被调度

}
type Option func(*Task)

type Runner interface {
	// 任务执行者预加载
	Preload(t *Task) error
	//任务执行者的唯一名称标识用于反序列化
	Name() types.RunnerName
	//任务执行者
	Run(t *Task) error
}

// NewTask 创建一个新的任务实例
//
// ctx: 应用上下文
// name: 任务名称
// runner: 任务执行器名称
// option: 可选的任务配置参数
//
// 返回值: 新创建的任务实例
func NewTask(ctx *core.AppContext, name types.TaskName, runner types.RunnerName, option ...Option) *Task {
	task := &Task{
		ctx:              ctx,
		id:               tools.GetMd5(string(name)),
		name:             name,
		single:           false,
		runOnceWhenAdded: true,
		runMode:          types.RunOnce,
		corn:             CORN_EVERY_30M,
		priority:         0,
		RunnerName:       runner,
		params:           make(map[string]any), // 初始化 params
	}

	// 应用选项
	for _, opt := range option {
		opt(task)
	}

	return task
}

// WithParam 设置任务参数
//
// 为任务添加一个键值对参数，可在任务执行时通过GetParam方法获取
// key: 参数键名
// param: 参数值
func WithParam(key string, param any) Option {
	return func(t *Task) {
		if t.params == nil {
			t.params = make(map[string]any)
		}
		// 只有当 params 不为 nil 时才设置
		if param != nil {
			t.params[key] = param
		}
	}
}
func WithRunOnceWhenAdded(runOnceWhenAdded bool) Option {
	return func(t *Task) {
		t.runOnceWhenAdded = runOnceWhenAdded
	}
}

// WithParams 批量设置任务参数
//
// 使用提供的参数映射批量设置任务参数
// params: 包含多个键值对参数的映射
func WithParams(params map[string]any) Option {
	return func(t *Task) {
		if t.params != nil {
			t.params = params
		}

	}
}

// WithPriority 设置任务优先级
//
// priority: 任务优先级数值，数值越大优先级越高
func WithPriority(priority int) Option {
	return func(t *Task) {
		t.priority = priority
	}
}

// WithRunModeOnce 设置任务为一次性运行模式
//
// 将任务设置为一次性运行模式，任务只会被执行一次
func WithRunModeOnce() Option {
	return func(t *Task) {
		t.runMode = types.RunOnce
		t.corn = ""
	}
}

// WithRunModeCorn 设置任务为定时运行模式
//
// corn: Cron表达式，定义任务的执行时间规则
func WithRunModeCorn(corn TaskCorn) Option {
	return func(t *Task) {
		t.corn = corn
		t.runMode = types.RunCorn
	}
}

// WithRunModeCorn30Min 设置任务为每30分钟执行一次的定时任务
func WithRunModeCorn30Min() Option {
	return WithRunModeCorn(CORN_EVERY_30M)
}

// WithRunModeCorn20Min 设置任务为每20分钟执行一次的定时任务
func WithRunModeCorn20Min() Option {
	return WithRunModeCorn(CORN_EVERY_20M)

}

// WithRunModeCorn10Min 设置任务为每10分钟执行一次的定时任务
func WithRunModeCorn10Min() Option {
	return WithRunModeCorn(CORN_EVERY_10M)

}

// WithRunModeCorn1Min 设置任务为每分钟执行一次的定时任务
func WithRunModeCorn1Min() Option {
	return WithRunModeCorn(CORN_EVERY_1M)

}

// WithRunModeCorn5Min 设置任务为每5分钟执行一次的定时任务
func WithRunModeCorn5Min() Option {
	return WithRunModeCorn(CORN_EVERY_5M)

}

// WithSingle 设置任务是否为单例模式
//
// single: true表示任务为单例模式，同一时间只能有一个实例运行；
//
//	false表示允许多个实例同时运行
func WithSingle(single bool) Option {
	return func(t *Task) {
		t.single = single
	}
}

// WithParent 设置父任务
//
// ptask: 父任务实例，用于建立任务间的层级关系
func WithParent(ptask *Task) Option {
	return func(t *Task) {
		t.pid = ptask.id
	}
}

// WithDelay 设置任务延时执行时间
//
// delay: 延时时间，任务将在指定时间后执行
func WithDelay(delay time.Duration) Option {
	return func(t *Task) {
		t.delay = delay
	}
}
func WithDelay5min() Option {
	return WithDelay(5 * time.Minute)
}
func WithDelay10min() Option {
	return WithDelay(10 * time.Minute)
}
func withDelay1Min() Option {
	return WithDelay(time.Minute)
}
func WithDelay1h() Option {
	return WithDelay(time.Hour)
}

// WithDelayUntil 设置在指定时间执行
func WithDelayUntil(executeTime time.Time) Option {
	return func(t *Task) {
		t.delay = time.Until(executeTime)
		if t.delay < 0 {
			t.delay = 0
		}
	}
}

// WithId 设置任务ID
//
// id: 自定义任务ID字符串
func (task *Task) WithId(id string) Option {
	return func(t *Task) {
		t.id = tools.GetMd5(id)
	}
}

// saveTaskInfo 保存任务定义信息到数据库
//
// 将任务的定义信息保存到sp_task_info表中
func (task *Task) saveTaskInfo() error {
	if task.info == nil {
		taskInfo := GetTaskInfoByTaskId(task.ctx.DB, task.id)
		task.info = taskInfo
	}

	task.syncTaskInfo()
	task.info.Save(task.ctx.DB)
	return nil
}

//保存任务运行记录

func (task *Task) saveTaskRecord() error {
	task.syncTaskRecord()
	task.record.Save(task.ctx.DB)
	return nil
}
func (task *Task) Logger() *slog.Logger {
	if task.logger == nil {
		return logger.Default()
	}
	return task.logger
}
func (task *Task) TaskManager() *TaskManager {
	return task.mgr
}
func (task *Task) GetCtx() *core.AppContext {
	return task.ctx
}
func (task *Task) GetParamInt(key string) int {
	return task.params[key].(int)
}

func GetParam[T any](task *Task, key string) T {
	if val, ok := task.params[key]; ok {
		// 尝试直接转换
		if result, ok := val.(T); ok {
			return result
		}

		// 如果直接转换失败，尝试处理类型不匹配的情况
		// 特别处理从JSON反序列化后数字类型变成float64的情况
		var zero T
		switch any(zero).(type) {
		case types.SourceId:
			// 处理SiteId类型
			if f, ok := val.(float64); ok {
				return any(types.SourceId(int(f))).(T)
			}
		case types.OriginId:
			// 处理OriginId类型
			if f, ok := val.(float64); ok {
				return any(types.OriginId(int(f))).(T)
			}
		case int:
			// 处理int类型
			if f, ok := val.(float64); ok {
				return any(int(f)).(T)
			}
		}
	}
	var zero T
	return zero
}

// SetResult 设置任务执行结果
//
// key: 结果键名
// value: 结果值
func (task *Task) SetResult(key string, value any) *Task {
	if task.result == nil {
		task.result = make(map[string]any)
	}
	task.result[key] = value
	return task
}
func (task *Task) SetResultError(value error) *Task {
	if task.result == nil {
		task.result = make(map[string]any)
	}
	if value == nil {
		return task
	}
	err := value.Error()
	task.result["error"] = err
	return task
}

// GetId 获取任务ID
func (task *Task) GetId() string {
	return task.id
}

// GetResult 获取任务执行结果
//
// key: 结果键名
// 返回值: 对应键名的结果值，如果不存在则返回nil
func (task *Task) GetResult(key string) any {
	if task.result == nil {
		return nil
	}
	return task.result[key]
}

// GetAllResults 获取所有任务执行结果
//
// 返回值: 包含所有结果的映射
func (task *Task) GetAllResults() map[string]any {
	return task.result
}

// syncTaskInfo 同步任务信息到TaskInfo
func (task *Task) syncTaskInfo() {
	if task.info == nil {
		task.info = &TaskInfo{
			TaskId:     task.id,
			PId:        task.pid,
			TaskName:   task.name,
			Single:     task.single,
			RunMode:    task.runMode,
			Corn:       task.corn,
			Priority:   task.priority,
			RunnerName: task.RunnerName,
			Params:     tools.ToJson(task.params),
		}
	} else {
		task.info.Single = task.single
		task.info.RunMode = task.runMode
		task.info.Corn = task.corn
		task.info.Priority = task.priority
		task.info.Params = tools.ToJson(task.params)
	}
}

// syncTaskRecord 同步任务状态到TaskRecord
func (task *Task) syncTaskRecord() {
	if task.record == nil {
		task.record = &TaskRunInfo{
			TaskId:   task.id,
			TaskName: task.name,
			Params:   tools.ToJson(task.params),

			StartTime: sql.NullTime{Time: task.startTime, Valid: !task.startTime.IsZero()},
			EndTime:   sql.NullTime{Time: task.endTime, Valid: !task.endTime.IsZero()},
			State:     task.state,
		}
	} else {

		task.record.StartTime = sql.NullTime{Time: task.startTime, Valid: !task.startTime.IsZero()}
		task.record.EndTime = sql.NullTime{Time: task.endTime, Valid: !task.endTime.IsZero()}
		task.record.State = task.state
		task.record.Result = tools.ToJson(task.result) // 更新任务执行结果

	}
}

// 定义任务副本
//
// 定义任务实际在执行时,需要创建一个副本任务,用于实际的执行
func (task *Task) copyForCornRunTask() *Task {
	return &Task{
		ctx:     task.ctx,
		mgr:     task.mgr,
		id:      task.id,  // 生成新的唯一ID
		pid:     task.pid, // 设置父任务ID为原始任务ID
		name:    task.name,
		single:  task.single,
		runMode: types.RunOnce, // 副本任务作为一次性任务执行,不需要指定corn
		//corn:       task.corn, //
		priority:         task.priority,
		RunnerName:       task.RunnerName,
		runOnceWhenAdded: false,
		params:           task.params,
		state:            types.TaskStatusInit,
		record:           nil, // 新任务需要新的记录
	}
}
